package cn.zxf.note.security;

import cn.zxf.note.common.exception.BizException;
import cn.zxf.note.security.dto.BindDto;
import cn.zxf.note.security.dto.RegisterDto;
import cn.zxf.note.security.dto.ResetPasswordDto;
import cn.zxf.note.security.platform.LoginRequest;
import cn.zxf.note.security.platform.LoginResult;
import cn.zxf.note.security.platform.PlatformLoginService;
import cn.zxf.note.user.addition.UserAdditionService;
import cn.zxf.note.user.platform.PlatformEnum;
import cn.zxf.note.user.platform.UserPlatformSupport;
import cn.zxf.note.user.question.UserQuestion;
import cn.zxf.note.user.question.UserQuestionSupport;
import cn.zxf.note.user.user.User;
import cn.zxf.note.user.user.UserRepository;
import cn.zxf.note.user.user.UserStatusEnum;
import cn.zxf.note.user.user.UserTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import jakarta.transaction.Transactional;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Pattern;

/**
 * Created by zengxf on 2020/5/15.
 */
@Slf4j
@Component
public class SecurityService {

    @Autowired
    private UserRepository repos;
    @Autowired
    private List<PlatformLoginService> loginServices;
    @Autowired
    private UserPlatformSupport userPlatformSupport;
    @Autowired
    private UserQuestionSupport userQuestionSupport;
    @Autowired
    private UserAdditionService userAdditionService;

    private static Pattern EMAIL_PATTERN = Pattern.compile(".+?@.+?\\..+");


    public Map<String, Object> login(Map<String, String> map) {
        log.info("login-map: {}", map);

        String account = map.get("account");
        String password = map.get("password");
        if (StringUtils.isEmpty(account) || StringUtils.isEmpty(password))
            throw BizException.of("账号和密码不能为空");

        User user = repos.login(account);
        if (user == null)
            return Map.of("login", "error");
        if (!Objects.equals(user.getPassword(), SecretUtils.encrypt(password)))
            return Map.of("login", "error");
        if (!Objects.equals(user.getStatus(), UserStatusEnum.NORMAL.code))
            throw BizException.of("账号已冻结");

        boolean remember = Boolean.parseBoolean(map.get("remember"));
        String token = TokenUtils.generate(user.getId(), remember);
        return Map.of("login", "ok", "token", token);
    }

    public LoginResult platformLogin(Map<String, String> map) {
        log.info("login-map: {}", map);

        String code = map.get("code");
        String platform = map.get("platform");
        if (StringUtils.isEmpty(code) || StringUtils.isEmpty(platform))
            return LoginResult.ERROR;

        LoginRequest request = new LoginRequest().setCode(code);
        PlatformEnum platformEnum = PlatformEnum.find(platform);
        PlatformLoginService service = loginServices.stream()
                .filter(ser -> platformEnum == ser.getPlatform())
                .findFirst()
                .orElseThrow(() -> BizException.of("还不支持此平台快捷登录"));
        LoginResult result = service.login(request);
        return result;
    }

    @Transactional
    public Map<String, String> bind(BindDto dto) {
        if (StringUtils.isEmpty(dto.getPlatform()) || StringUtils.isEmpty(dto.getOpenId()))
            throw BizException.of("Fuck You!");
        PlatformEnum.find(dto.getPlatform()); // validate
        if (StringUtils.isEmpty(dto.getAccount()) || StringUtils.isEmpty(dto.getPassword()))
            throw BizException.of("账号和密码不能为空");

        User user;
        if (BooleanUtils.isNotTrue(dto.getExist())) {
            if (StringUtils.isEmpty(dto.getEmail()) || StringUtils.isEmpty(dto.getNick()))
                throw BizException.of("邮箱和昵称不能为空");
            if (!EMAIL_PATTERN.matcher(dto.getEmail()).find())
                throw BizException.of("邮箱格式不对");
            if (StringUtils.isEmpty(dto.getQa1()) || StringUtils.isEmpty(dto.getQa2()) || StringUtils.isEmpty(dto.getQa3()))
                throw BizException.of("密保不能为空");
            User user1 = repos.login(dto.getAccount());
            User user2 = repos.login(dto.getEmail());
            if (user1 != null || user2 != null)
                throw BizException.of("账号或邮箱已存在");

            user = new User()
                    .setAccountNumber(dto.getAccount())
                    .setEmail(dto.getEmail())
                    .setPassword(SecretUtils.encrypt(dto.getPassword()))
                    .setStatus(UserStatusEnum.NORMAL.code)
                    .setType(UserTypeEnum.NORMAL.code);
            repos.save(user);
            userAdditionService.save(user.getId(), dto.getNick());
            userQuestionSupport.save(user.getId(), dto.getQa1(), dto.getQa2(), dto.getQa3());
        } else {
            user = repos.login(dto.getAccount());
            if (user == null)
                return Map.of("bind", "error");
            if (!Objects.equals(user.getPassword(), SecretUtils.encrypt(dto.getPassword())))
                return Map.of("bind", "error");
            if (!Objects.equals(user.getStatus(), UserStatusEnum.NORMAL.code))
                throw BizException.of("账号已冻结");
        }
        userPlatformSupport.save(dto.getPlatform(), dto.getOpenId(), user.getId());
        String token = TokenUtils.generate(user.getId(), true);
        return Map.of("bind", "ok", "token", token);
    }

    @Transactional
    public Map<String, String> register(RegisterDto dto) {
        if (StringUtils.isEmpty(dto.getAccount()) || StringUtils.isEmpty(dto.getPassword()))
            throw BizException.of("账号和密码不能为空");
        if (StringUtils.isEmpty(dto.getEmail()) || StringUtils.isEmpty(dto.getNick()))
            throw BizException.of("邮箱和昵称不能为空");
        if (StringUtils.isEmpty(dto.getQa1()) || StringUtils.isEmpty(dto.getQa2()) || StringUtils.isEmpty(dto.getQa3()))
            throw BizException.of("密保不能为空");
        if (!EMAIL_PATTERN.matcher(dto.getEmail()).find())
            throw BizException.of("邮箱格式不对");
        User user1 = repos.login(dto.getAccount());
        User user2 = repos.login(dto.getEmail());
        if (user1 != null || user2 != null)
            throw BizException.of("账号或邮箱已存在");

        User user = new User()
                .setAccountNumber(dto.getAccount())
                .setEmail(dto.getEmail())
                .setPassword(SecretUtils.encrypt(dto.getPassword()))
                .setStatus(UserStatusEnum.NORMAL.code)
                .setType(UserTypeEnum.NORMAL.code);
        repos.save(user);
        userAdditionService.save(user.getId(), dto.getNick());
        userQuestionSupport.save(user.getId(), dto.getQa1(), dto.getQa2(), dto.getQa3());
        String token = TokenUtils.generate(user.getId(), true);
        return Map.of("register", "ok", "token", token);
    }

    @Transactional
    public void resetPassword(ResetPasswordDto dto) {
        if (StringUtils.isEmpty(dto.getAccount()) || StringUtils.isEmpty(dto.getPassword()))
            throw BizException.of("账号和密码不能为空");
        if (StringUtils.isEmpty(dto.getQa1()) || StringUtils.isEmpty(dto.getQa2()) || StringUtils.isEmpty(dto.getQa3()))
            throw BizException.of("密保不能为空");
        User user = repos.login(dto.getAccount());
        if (user == null)
            throw BizException.of("账号或密保不对");
        UserQuestion uq = userQuestionSupport.findOne(user.getId());
        if (Objects.equals(dto.getQa1(), uq.getQa1())
                && Objects.equals(dto.getQa2(), uq.getQa2())
                && Objects.equals(dto.getQa3(), uq.getQa3())
        ) {
            user.setPassword(SecretUtils.encrypt(dto.getPassword()));
            repos.save(user);
        } else
            throw BizException.of("账号或密保不对");
    }

}
